package licode.unisop.oidc.authsa.service;

import cn.dev33.satoken.session.TokenSign;
import licode.unisop.oidc.auth.api.OidcSession;
import licode.unisop.oidc.auth.modal.*;
import licode.unisop.oidc.authsa.stp.SaAuthUtil;
import licode.unisop.oidc.authsa.stp.SaStpLogic;
import licode.unisop.oidc.authsa.stp.SaTokenSign;
import licode.unisop.oidc.authsa.utils.TokenUtil;
import lombok.Getter;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 实现会话的管理接口类
 *
 * @author licode
 */
@Getter
public class SaOidcSession implements OidcSession {
    /**
     * 组合sa-token的会话管理类
     */
    private final SaSessionProxy saSession;

    public SaOidcSession(SaSessionProxy saSession) {
        this.saSession = saSession;
    }

    @Override
    public String getUserId() {
        return saSession.getUserId();
    }

    @Override
    public String getSessionId() {
        return saSession.getId();
    }

    @Override
    public String getSessionToken() {
        return saSession.getToken();
    }

    @Override
    public int getSsoLoginCount() {
        return null == saSession.getSsoToken() ? 0 : saSession.calcSsoCount();
    }

    @Override
    public int getTerminalLoginCount(String platformId, String terminalId) {
        int loginCount = 0;
        String terminalCode = null == terminalId ? "" : terminalId;
        List<TokenSign> tokenList = saSession.tokenSignListCopy();
        if (null != tokenList && !tokenList.isEmpty()) {
            for (TokenSign token : tokenList) {
                AuthorContext context = SaAuthUtil.loginContextFromAccessToken(token.getValue());
                if (null != context && platformId.equals(context.getPid())) {
                    if (terminalCode.equals(context.getTid())) {
                        ++loginCount;
                    }
                }
            }
        }
        return loginCount;
    }

    @Override
    public void tickOffTerminalLogin(String platformId, String terminalId) {
        String terminalCode = null == terminalId ? "" : terminalId;
        List<TokenSign> tokenList = saSession.tokenSignListCopy();
        if (null != tokenList && !tokenList.isEmpty()) {
            for (TokenSign token : tokenList) {
                SaTokenSign tokenSign = (SaTokenSign)token;
                if (null == tokenSign.getSsoToken()) {
                    AuthorContext context = SaAuthUtil.loginContextFromAccessToken(token.getValue());
                    if (null != context && platformId.equals(context.getPid())) {
                        if (terminalCode.equals(context.getTid())) {
                            SaAuthUtil.logoutByAccessToken(token.getValue(), saSession);
                        }
                    }
                }
            }
        }
    }

    @Override
    public long getCreateTime() {
        return saSession.getCreateTime();
    }

    @Override
    public Long getExpiredTime() {
        return saSession.getTimeout();
    }

    @Override
    public OidcToken getTokenInfo(AccessTokenId accessToken) {
        return saSession.tokenInfoFromAccessToken(accessToken.getAccessToken());
    }

    @Override
    public OidcToken getFirstSsoTokenInfo(String ssoToken) {
        List<TokenSign> tokenList = saSession.tokenSignListCopy();
        if (null != tokenList && !tokenList.isEmpty()) {
            for (TokenSign token : tokenList) {
                SaTokenSign saToken = (SaTokenSign) token;
                if (ssoToken.equals(saToken.getSsoToken())) {
                    AuthorContext context;
                    context = SaAuthUtil.loginContextFromAccessToken(token.getValue());
                    return TokenUtil.fromTokenSign(saToken.getValue(), context);
                }
            }
        }

        return null;
    }

    @Override
    public void updateExpiredTime(long expiredTime, boolean updateSso) {
        saSession.updateSessionTimeout(expiredTime, updateSso);
    }

    @Override
    public Object getAttribute(String key) {
        return saSession.get(key);
    }

    @Override
    public void setAttribute(String key, Object value) {
        saSession.set(key, value);
    }

    private String millSecondToString(Long millSeconds) {
        if (null == millSeconds) {
            return "";
        } else {
            SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd HH:mm:ss");
            return sdf.format(new Date(millSeconds));
        }
    }

    @Override
    public SessionDetail getLoginInfo() {
        SaStpLogic stpLogic = SaAuthUtil.getStpLogic();
        SessionDetail sessionDetail = new SessionDetail();
        long sessionTime = this.saSession.getCreateTime();
        long sessionExpired = stpLogic.getSessionTimeoutByLoginId(this.saSession.getLoginId());

        String realmId = "";
        String userId = "";
        List<AuthorDetail> details = new ArrayList<>();
        List<TokenSign> tokenSigns = this.saSession.tokenSignListCopy();

        sessionDetail.setSessionToken(this.saSession.getToken());
        sessionDetail.setLoginId(this.saSession.getLoginId().toString());
        sessionDetail.setDetails(details);
        sessionDetail.setSessionTime(millSecondToString(sessionTime));
        sessionDetail.setSessionExpired(sessionExpired);

        if (null != tokenSigns) {
            for (TokenSign item : tokenSigns) {
                if (item instanceof SaTokenSign) {
                    SaTokenSign saToken = (SaTokenSign) item;
                    AuthorContext context = stpLogic.loginContextFromAccessToken(item.getValue());

                    if (null == stpLogic.loginIdFromAccessToken(saToken.getValue())) {
                        continue;
                    }

                    long loginTime = saToken.getCreateTime() == null ? 0 : saToken.getCreateTime();
                    realmId = context.getRid();
                    userId = context.getUid();
                    String lastRefreshTime = "";
                    int sso = saToken.getSsoToken() == null || saToken.getSsoToken().isEmpty() ? 0 : 1;
                    if (null != context.getLrt()) {
                        lastRefreshTime = millSecondToString(context.getLrt() * 1000);
                    }

                    details.add(AuthorDetail.builder()
                            .clientId(context.getCid())
                            .terminal(context.getTer())
                            .platformId(context.getPid())
                            .accessToken(saToken.getValue())
                            .isSso(sso)
                            .peerIp(context.getPip())
                            .account(context.getAc())
                            .authType(context.getAt())
                            .roleNames(context.getRn())
                            .loginMode(sso == 1 ? "单点登录" : "普通登录")
                            .refreshToken(saToken.getRefreshToken())
                            .tenantId(context.getTid())
                            .accessExpire(millSecondToString(saToken.getAccessExpire() * 1000))
                            .refreshExpire(millSecondToString(saToken.getRefreshExpire() * 1000))
                            .loginTime(millSecondToString(loginTime * 1000))
                            .lastRefreshTime(lastRefreshTime)
                            .build());
                }
            }
        }

        sessionDetail.setUserId(userId);
        sessionDetail.setRealmId(realmId);

        return sessionDetail;
    }

    @Override
    public void updateSession() {
        saSession.update();
    }

    @Override
    public void exitSession() {

    }

    @Override
    public void exitSsoSession() {

    }
}
